﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Serialization;
using Microsoft.Xna.Framework;

namespace NapazEngine.Utilities.Data
{
    [Serializable]
    public class Settings
    {
        /// <summary>
        /// Variables relating to the client specifically.
        /// </summary>
        [XmlElement("ClientVariables")]
        public List<Setting> ClientVariables { get; private set; }

        /// <summary>
        /// Sets a client variable value to a specified value
        /// </summary>
        /// <param name="name">Name of the variable</param>
        /// <param name="value">Value to set</param>
        public void SetClientVariableValue(string name, object value)
        {
            Setting setting = ClientVariables.Where(s => s.Name.Equals(name)).FirstOrDefault();
            setting.Value = value;
        }

        /// <summary>
        /// Sets a client variable description to a specified value
        /// </summary>
        /// <param name="name">Name of the variable</param>
        /// <param name="value">Value to set</param>
        public void SetClientVariableDescription(string name, string description)
        {
            Setting setting = ClientVariables.Where(s => s.Name.Equals(name)).FirstOrDefault();
            setting.Description = description;
        }

        /// <summary>
        /// Variables relating to servers and networking.
        /// May or may not actually get used depending on how the game turns out
        /// </summary>
        [XmlElement("ServerVariables")]
        public List<Setting> ServerVariables { get; private set; }
        
        /// <summary>
        /// provides a manager to handle settings
        /// </summary>
        public Settings()
        {
            ClientVariables = new List<Setting>();
            ServerVariables = new List<Setting>();

            AddClientVariables();
            AddServerVariables();
        }

        private void AddClientVariables()
        {
            // Graphics/Engine settings
            ClientVariables.Add(new Setting("fullscreen", Defaults.DEFAULT_FULLSCREEN, "Engine - Whether the game is in fullscreen"));
            ClientVariables.Add(new Setting("windowHeight", Defaults.DEFAULT_WINDOW_HEIGHT, "Engine - Height of the game window"));
            ClientVariables.Add(new Setting("windowWidth", Defaults.DEFAULT_WINDOW_WIDTH, "Engine - Width of the game window"));
            ClientVariables.Add(new Setting("synchronizeWithVerticalRetrace", Defaults.DEFAULT_SYNCHRONIZE_WITH_VERTICAL_RETRACE, "Engine - Whether to synchronize with vertical retrace"));
            ClientVariables.Add(new Setting("preferMultiSampling", Defaults.DEFAULT_PREFER_MULTI_SAMPLING, "Engine - Whether to prefer multi sampling"));

            // Engine timing settings
            ClientVariables.Add(new Setting("isFixedTimeStep", Defaults.IS_FIXED_TIME_STEP, "Engine - Whether updates occur in fixed time steps"));
            ClientVariables.Add(new Setting("updatesPerSecond", Defaults.UPDATES_PER_SECOND, "Engine - Number of updates per second when fixed time step is enabled"));

            // Graphics/Engine, helps for positioning graphics in 2D in multiple resolutions
            ClientVariables.Add(new Setting("widthScale", 1.0f, "Graphics - Scale of the width of the window. Useful for scaling in differing resolutions"));
            ClientVariables.Add(new Setting("heightScale", 1.0f, "Graphics - Scale of the height of the window. Useful for scaling in differing resolutions"));

            // Misc engine settings
            ClientVariables.Add(new Setting("printLog", Defaults.DEFAULT_PRINT_LOG, "Engine - Whether to print the log to the console"));
            ClientVariables.Add(new Setting("openingScreenTime", Defaults.DEFAULT_OPENING_SCREEN_TIME, "Engine - How long to keep the opening screen open"));

            // UI settings
            ClientVariables.Add(new Setting("uiBackgroundColor", new Color(Defaults.DEFAULT_UI_BACKGROUND_COLOR_R, Defaults.DEFAULT_UI_BACKGROUND_COLOR_G, Defaults.DEFAULT_UI_BACKGROUND_COLOR_B), "UI - Menu screens background color"));
            ClientVariables.Add(new Setting("textButtonColor", new Color(Defaults.DEFAULT_TEXT_BUTTON_COLOR_R, Defaults.DEFAULT_TEXT_BUTTON_COLOR_G, Defaults.DEFAULT_TEXT_BUTTON_COLOR_B), "UI - Menu screens text button colors"));
            ClientVariables.Add(new Setting("textButtonHoverColor", new Color(Defaults.DEFAULT_TEXT_BUTTON_HOVER_COLOR_R, Defaults.DEFAULT_TEXT_BUTTON_HOVER_COLOR_G, Defaults.DEFAULT_TEXT_BUTTON_HOVER_COLOR_B), "UI - Menu screens text button hover color"));
            ClientVariables.Add(new Setting("textLabelColor", new Color(Defaults.DEFAULT_TEXT_LABEL_COLOR_R, Defaults.DEFAULT_TEXT_LABEL_COLOR_G, Defaults.DEFAULT_TEXT_LABEL_COLOR_B), "UI - Menu screens text label color"));
            ClientVariables.Add(new Setting("dropShadowColor", new Color(Defaults.DEFAULT_DROPSHADOW_COLOR_R, Defaults.DEFAULT_DROPSHADOW_COLOR_G, Defaults.DEFAULT_DROPSHADOW_COLOR_B), "UI - Menu screens text label dropshadow color"));
            
            // Client Mouse settings
            ClientVariables.Add(new Setting("mouseInverted", Defaults.DEFAULT_MOUSE_INVERTED, "Engine - Whether the mouse is inverted"));
            ClientVariables.Add(new Setting("mouseSensitivity", Defaults.DEFAULT_MOUSE_SENSITIVITY, "Engine - Sensitivity of the mouse"));
            ClientVariables.Add(new Setting("mouseSensitivityHorizontal", Defaults.DEFAULT_MOUSE_SENSITIVITY_HORIZONTAL, "Engine - Sensitivity of the mouse in the horizontal direction"));
            ClientVariables.Add(new Setting("mouseSensitivityVertical", Defaults.DEFAULT_MOUSE_SENSITIVITY_VERTICAL, "Engine - Sensitivity of the mouse in the vertical direction"));

            // settings not needed for 2D
            ClientVariables.Add(new Setting("fieldOfView", Defaults.DEFAULT_FIELD_OF_VIEW, "3d - Field of view"));
            ClientVariables.Add(new Setting("aspectRatio", Defaults.DEFAULT_ASPECT_RATIO, "3d - Aspect ratio"));
            ClientVariables.Add(new Setting("nearPlane", Defaults.DEFAULT_NEAR_PLANE, "3d - How close the near plane is"));
            ClientVariables.Add(new Setting("farPlane", Defaults.DEFAULT_FAR_PLANE, "3d - How far the far plane is"));

            // Misc graphics settings
            ClientVariables.Add(new Setting("drawHitboxes", Defaults.DEFAULT_DRAW_HITBOXES, "3d - Whether to draw hitboxes on models"));
            ClientVariables.Add(new Setting("wireframeMode", Defaults.DEFAULT_WIREFRAME_MODE, "3d - Whether to draw in wireframe mode"));
        }

        private void AddServerVariables()
        {

        }

        /// <summary>
        /// Sets a server variable value to a specified value
        /// </summary>
        /// <param name="name">Name of the variable</param>
        /// <param name="value">Value to set</param>
        public void SetServerVariableValue(string name, object value)
        {
            Setting setting = ServerVariables.Where(s => s.Name.Equals(name)).FirstOrDefault();
            setting.Value = value;
        }

        /// <summary>
        /// Sets a server variable description to a specified value
        /// </summary>
        /// <param name="name">Name of the variable</param>
        /// <param name="value">Value to set</param>
        public void SetServerVariableDescription(string name, string description)
        {
            Setting setting = ServerVariables.Where(s => s.Name.Equals(name)).FirstOrDefault();
            setting.Description = description;
        }

        /// <summary>
        /// Gets a setting from the list of client variables
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public Setting GetClientSetting(string name)
        {
            return ClientVariables.Where(s => s.Name.Equals(name)).FirstOrDefault();
        }

        /// <summary>
        /// Gets a setting from the list of server variables
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public Setting GetServerSetting(string name)
        {
            return ServerVariables.Where(s => s.Name.Equals(name)).FirstOrDefault();
        }
    }
}
